package com.autumn.context.io;

import com.autumn.context.utils.YamlUtils;
import org.jetbrains.annotations.Nullable;

import java.io.FileInputStream;
import java.io.IOException;
import java.time.*;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.function.Function;

/**
 * @author niann
 * @description 获取配置信息
 * @date 2023/12/20 12:10
 */
public class PropertyResolver {
    private final Map<String, String> property = new HashMap<>();
    private final Map<Class, Function<String, Object>> converters = new HashMap<>();


    public PropertyResolver(Properties prop) {
        this.property.putAll(System.getenv());
        Set<String> props = prop.stringPropertyNames();
        if (props != null) {
            for (String s : props) {
                this.property.put(s, prop.getProperty(s));
            }
        }
        registerConverters();
    }

    public static void main(String[] args) {
        Properties prop = new Properties();
        prop.put("com.nn", "年年");
        prop.put("app.年年", "哈哈哈");
        PropertyResolver pr = new PropertyResolver(prop);
        System.out.println(pr.getProperty("${app.com.nn:${app.${com.nn}}}"));
    }

    public static PropertyResolver readConfigurationFile(String path) {
        Properties properties = new Properties();
        try {
            FileInputStream fileInputStream = new FileInputStream(path);
            properties.load(fileInputStream);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        PropertyResolver props = new PropertyResolver(properties);
        return props;
    }

    public static PropertyResolver readYamlFile(String path) {
        Properties properties = new Properties();
        Map<String, Object> map = YamlUtils.loadYaml(path);
        properties.putAll(map);
        return new PropertyResolver(properties);
    }

    private void registerConverters() {
        // String类型:
        converters.put(String.class, s -> s);
        // boolean类型:
        converters.put(boolean.class, Boolean::parseBoolean);
        converters.put(Boolean.class, Boolean::valueOf);
        // int类型:
        converters.put(int.class, Integer::parseInt);
        converters.put(Integer.class, Integer::valueOf);
        // 其他基本类型...
        // Date/Time类型:
        converters.put(LocalDate.class, LocalDate::parse);
        converters.put(LocalTime.class, LocalTime::parse);
        converters.put(LocalDateTime.class, LocalDateTime::parse);
        converters.put(ZonedDateTime.class, ZonedDateTime::parse);
        converters.put(Duration.class, Duration::parse);
        converters.put(ZoneId.class, ZoneId::of);
        converters.put(ZoneOffset.class, ZoneOffset::of);
        converters.put(Period.class, Period::parse);
        converters.put(Instant.class, Instant::parse);
        converters.put(OffsetDateTime.class, OffsetDateTime::parse);
        converters.put(OffsetTime.class, OffsetTime::parse);
    }

    public <T> void registerConverters(Class<T> clazz, Function<String, Object> fun) {
        converters.put(clazz, fun);
    }

    @Nullable
    public <T> T getProperty(String key, Class<T> clazz) {
        String value = getProperty(key);
        return value == null ? null : convert(key, clazz);
    }

    public String getProperty(String key) {
        Property prop = parseProperty(key);
        String k = prop.key();
        String val = this.property.get(k);
        if (val == null) {
            String defaultValue = prop.defaultValue();
            if (defaultValue != null && defaultValue.startsWith("${") && defaultValue.endsWith("}")) {
                return getProperty(defaultValue);
            }
            if (defaultValue != null && defaultValue.endsWith("}")) {
                return defaultValue.substring(0, defaultValue.length() - 1);
            }
            return defaultValue;
        }
        return val;
    }

    private <T> T convert(String value, Class<T> clazz) {
        Function<String, Object> function = converters.get(clazz);
        if (function == null) {
            throw new RuntimeException("不支持的类型:{%s}".formatted(clazz.getName()));
        }
        return (T) function.apply(value);
    }

    private Property parseProperty(String key) {
        if (key.startsWith("${")) {
            int i = key.indexOf(":");
            String defaultVal = null;
            if (i != -1) {
                defaultVal = key.substring(i + 1, key.length() - 1);
                key = key.substring(2, i);
            } else {
                key = key.substring(2, key.length() - 1);
            }
            if (key.contains("${")) {
                return builderProperty(key, defaultVal);
            }
            return new Property(key, defaultVal);
        }
        return new Property(key, null);
    }

    private Property builderProperty(String key, String defaultValue) {
        int i = key.indexOf("${");
        String prifix = key.substring(0, i);
        String substring = key.substring(i);
        Property prop = parseProperty(substring);
        String k = prop.key();
        String subKey = getProperty(k);
        return new Property(prifix + subKey, defaultValue);
    }


}
